import { db } from '@/db'
import { videos } from '@/db/schema'
import { mux } from '@/lib/mux'
import {
  VideoAssetCreatedWebhookEvent,
  VideoAssetErroredWebhookEvent,
  VideoAssetReadyWebhookEvent,
  VideoAssetTrackReadyWebhookEvent,
  VideoAssetDeletedWebhookEvent
} from '@mux/mux-node/resources/webhooks'
import { eq } from 'drizzle-orm'
import { headers } from 'next/headers'
import { UTApi } from 'uploadthing/server'

const SIGNING_SECRET = process.env.MUX_WEBHOOK_SECRET

type WebhookEvent =
  | VideoAssetCreatedWebhookEvent
  | VideoAssetErroredWebhookEvent
  | VideoAssetReadyWebhookEvent
  | VideoAssetTrackReadyWebhookEvent
  | VideoAssetDeletedWebhookEvent

export const POST = async (req: Request) => {
  if (!SIGNING_SECRET) throw new Error('MUX_WEBHOOK_SECRET is not set')

  const headersPayload = await headers()
  const signature = headersPayload.get('mux-signature')

  if (!signature)
    return new Response('mux-signature header is not set', { status: 401 })

  const payload = await req.json()
  const body = JSON.stringify(payload)

  mux.webhooks.verifySignature(
    body,
    {
      'mux-signature': signature
    },
    SIGNING_SECRET
  )

  switch (payload.type as WebhookEvent['type']) {
    case 'video.asset.created': {
      const data = payload.data as VideoAssetCreatedWebhookEvent['data']
      if (!data.upload_id)
        return new Response('upload_id is not set', { status: 400 })
      await db
        .update(videos)
        .set({
          muxAssetId: data.id,
          muxStatus: data.status
        })
        .where(eq(videos.muxUploadId, data.upload_id))
      break
    }

    case 'video.asset.ready': {
      const data = payload.data as VideoAssetReadyWebhookEvent['data']
      const playbackId = data.playback_ids?.[0]?.id

      if (!data.upload_id)
        return new Response('upload_id is not set', { status: 400 })

      if (!playbackId)
        return new Response('playback_id is not set', { status: 400 })

      const tempThumbnailUrl = `https://image.mux.com/${playbackId}/thumbnail.jpg`
      const tempPreviewUrl = `https://image.mux.com/${playbackId}/animated.gif`
      const duration = data.duration ? Math.round(data.duration * 1000) : 0

      const utapi = new UTApi()
      const [uploadThumbnailUrl, uploadPreviewUrl] =
        await utapi.uploadFilesFromUrl([tempThumbnailUrl, tempPreviewUrl])

      if (!uploadThumbnailUrl || !uploadPreviewUrl)
        return new Response('upload failed', { status: 500 })

      const { key: thumbnailKey, url: thumbnailUrl } =
        uploadThumbnailUrl.data || {}
      const { key: previewKey, url: previewUrl } = uploadPreviewUrl.data || {}

      await db
        .update(videos)
        .set({
          muxAssetId: data.id,
          muxPlaybackId: playbackId,
          muxStatus: data.status,
          thumbnailUrl,
          thumbnailKey,
          previewUrl,
          previewKey,
          duration
        })
        .where(eq(videos.muxUploadId, data.upload_id))
      break
    }

    case 'video.asset.errored': {
      const data = payload.data as VideoAssetErroredWebhookEvent['data']
      if (!data.upload_id)
        return new Response('upload_id is not set', { status: 400 })
      await db
        .update(videos)
        .set({
          muxStatus: data.status
        })
        .where(eq(videos.muxUploadId, data.upload_id))
      break
    }

    case 'video.asset.deleted': {
      const data = payload.data as VideoAssetDeletedWebhookEvent['data']
      if (!data.upload_id)
        return new Response('upload_id is not set', { status: 400 })
      await db.delete(videos).where(eq(videos.muxUploadId, data.upload_id))
      break
    }

    case 'video.asset.track.ready': {
      const data = payload.data as VideoAssetTrackReadyWebhookEvent['data'] & {
        asset_id: string
      }
      const assetId = data.asset_id
      const trackId = data.id
      const status = data.status

      if (!assetId) return new Response('asset_id is not set', { status: 400 })

      await db
        .update(videos)
        .set({
          muxTrackId: trackId,
          muxTrackStatus: status
        })
        .where(eq(videos.muxAssetId, assetId))
      break
    }
  }
  return new Response('webhook received', { status: 200 })
}
